Programando o Framework do Direct3D 7 IM Parte 2 
Por Wolfgang Engel 



Prefcio


Voc pode lembrar-se disto no primeiro tutorial "O Bsico", ns determinamos que todas os exemplos que so construdos com Framwork do Direct3D no DirectX SDK so criados ao fornecer verses sobrecarregadas dos mtodos de CD3DApplication :

...
ConfirmDevice()
OneTimeSceneInit()
InitDeviceObjects()
FrameMove()
Render()
DeleteDeviceObjects()
FinalCleanup()
...

Tambm aprendemos a tarefa de todos os mtodos na classe de framework.

Neste tutorial comearemos a escrever nosso primeiro app com animao. Mostrar um objeto amarelo e vermelho que pode ser girado em suas axis x e y. A aplicao usa um Z-Buffer e a mais simples interface de teclado que possa imaginar. Voc pode mover e girar a cmera para cima, para baixo, esquerda, direita e teclas c e x. A entrada  manuseada via DirectInput. O movimento da cmera parece um pouco com os primeiros jogos X-Wing. S ficar faltando um espao para voc explorar :-). 

Esta  uma resposta a muitos e- mails que recebi. Os leitores da primeira verso deste tutorial queriam saber como girar e mover mais que um objeto em uma cena independente.

Como sempre, voc pode alternar entre tela cheia e janela com ALT-F4. F1 mostrar a voc a caixa de dilogo Sobre este aplicativo, F2 voc pode selecionar os drives disponveis e ESC fechar o app. 

Para compilar o cdigo d uma olhada no O tutorial bsico . Tenha certeza tambm de linkar o dinput.lib ao seu projeto. 

Pegue o cdigo fonte aqui.

Uma das melhores maneiras de aprender como usar as transformaes do mundo com o Direct3D  o exemplo "Boids" do DirectX 7 SDK. Descobri um bom tutorial sobre orientao de cmera com Direct3DX no Mr. Gamemaker. Outros documentos interessantes sobre orientao de cmera esto em flipCode, CrystalSpace, Dave's Math Tables e as pginas sobre Geometria de Paul Bourke. Em adio, as pginas de Mayhem sobre Matrizes e  claro o livro de John de Goes sobre Direct3D 3D Game Programming with C++ so teis. Para aparte do DirectInput , descobri Tricks of the Windows Game Programming Gurus (Truques dos Gurus em Programao de Jogos Windows) de Andr LaMothe, muito til.

A terceira dimeno
Voc precisa ter uma boa familiaridade com princpios geomtricos 3D para programar as aplicaes Direct3D . O primeiro passo no entendimento destes princpios  entender a linha (pipeline) de transformao como parte da linha (pipeline) de apresentao.




A figura mostra a linha do Direct3D .

A sombra (shader) da unidade da vrtice ser introduzida em um dos primeiros tutoriais depois que o DirectX 8 for lanado. No caso da Unidade de Processamento de Grficos Geforce2,  um motor (engine) SIMD programvel com armazenagem de 192 quadwords de dados e 128 app-downloadable de intrues, que especifica as tarefas executadas em cada vrtice. Pode fazer as transformaes padro, cliping, dobramento de vrtices, morphing, animao, skinning, neblina elevada, deformao de malha, gerao de coordenadas de textura procedural tais como mapas e iluminao.

Uma Observao para a Linha (Pipeline) T & I (Texturizao & Iluminao): Imagine que o processo de texturizao e iluminao so como uma linha de montagem em uma fbrica, na qual vrtices no transformadas e no iluminadas entram, e depois vrias operaes seqenciais so realizadas sobre elas. No final da linha de montagem saem vrtices transformadas e iluminadas. Muitos programadores implementaram seus prprios algoritmos de transformao e iluminao. Eles podem desabilitar partes desta linha e enviar as vrtices que j esto transformadas e iluminadas para o Direct3D. 

Mas na maioria dos casos ser melhor usar a linha do Direct3D T&I, porque  na verdade rpido especialmente com os novos drivers grficos T&I, que so fornecidos com os conjuntos de chips do Geforce e Savage 2000. 

Estes processadores grficos ganharam um importante papel nos ltimos anos. A maioria das tarefas da linha de apresentao est agora computada por uma unidade de processamento grfico.



Antigamente, funes de transformao e iluminao da linha do 3D eram realizadas pela CPU do PC. Desde 1999, esto disponveis Placas 3D com hardware dedicado a acelerao T&I. Com estas placas  possvel uma performance grfica mais alta, porque elas podem processar funes grficas com velocidade superior a quatro vezes a das CPUs liderantes. Por outro lado, a CPU pode agora ser melhor utilizada para funes tais como: inteligncia artificial (IA) sofisticada, elementos do jogo fsicos e mais complexos. Assim, a nova gerao de placas fornecer muita fora para a nova gerao de jogos.  uma tima hora para os programadores de jogos :-) 



Pipeline de transformao
 uma tarefa complexa descrever e mostrar objetos e ambientes grficos em 3D. Descrever os dados 3D de acordo com os diferentes quadros de referncia ou diferentes sistemas de coordenadas reduz a complexidade. Estes quadros de referncia diferentes so chamados "espaos" tais como model space (espao do modelo), world space (espao do mundo), view space (espao da viso), projection space (espao da projeo). Por causa destes espaos usamos diferentes sistemas de coordenadas; dados 3D devem ser convertidos ou transformados de um espao para outro. 



A pipeline de transformao transforma cada vrtice do objeto de um abstrato, a coordenada de um ponto flutuante no espao  um pixel base na tela, levando em conta as propriedades da cmera virtual usada para apresentar a cena. Esta transformao  feita com trs matrizes de transformao: a do mundo (world), a da viso (view) e a de projeo da matriz (projection). O uso destas transformaes assegura que o Direct3D somente tenha que trabalhar com um sistema de coordenadas a cada passo. Entre estes passos, os objetos so orientados de uma maneira uniforme.

O estgio do world transformation (transformao do mundo) transforma um objeto do modelo ou objeto do espao do mundo. Model space (espao do modelo)  a coordenada espacial na qual um objeto  definido, independente de outros objetos e do mundo em si. No model space, os pontos do modelo ou objeto so rotacionados, escalados e traduzidos para anim-lo. Por exemplo, pense no modelo Quake 3, que gira seu torso e segura sua arma na sua direo. Com model space  mais fcil e mais rpido mover um objeto simplesmente ao redefinir a transformao do modelo para o world space do que seria um mudar manualmente todas as coordenadas do objeto no world space. Por exemplo, para girar uma esfera ou um cubo sobre seu centro parece mais natural e  muito mais fcil quando a origem est no centro do objeto, no levando em conta onde no world space o objeto esteja posicionado. World space (espao do mundo)  um quadro de referncia absoluto para um mundo 3D; todas as localizaes dos objetos e orientaes esto em relao ao world space. Ele fornece uma coordenada de espao que todos os objetos dividem, ao invs de exigir um sistema nico de coordenadas para cada objeto. 

Para transformar os objetos do modelo para o world space, cada objeto ser girado sobre a x-axis, y-axis ou z-axis, escalado (aumentando ou encolhendo o objeto) e traduzido, ao mover o objeto ao longo da x-axis, y-axis, ou z-axis para a sua orientao, posio e tamanho final. 

Direct3D usa um sistema de coordenadas canhoto (OpenGL ultiliza o normal), no qual cada axix positiva (x, y ou z) est apontando para longe de quem est olhando. 



O estgio do view transformation (transformao da viso) transforma os objetos do world space em espao de cmera ou viso. Esta transformao coloca a cmera na origem e a aponta diretamente para baixo da z-axis positiva. A geometria tem de ser traduzida em formas 2D adequadas.  til tambm para a seleo da iluminao e da backface (face de trs). As coordenadas de luz que so especificadas no word space, so transformadas dentro do espao da cmera neste estgio e o efeito de luz  calculado e aplicado nas vrtices. 



A seleo do Backface acontece aqui. Seria uma perda de tempo da CPU desenhar a backface do cubo quando no est vsivel. Para omitir o desenho da backface  chamado de seleo da backface. Para selecionar a backface, precisamos determinar a visibilidade. Uma da maneiras mais simples  a seguinte: a face frontal  uma na qual as vrtices so definidas na ordem do sentido do relgio. Assim o Direct3D s desenha as faces com vrtices na ordem do sentido do relgio como padro. Para modificar a seleo do backface, use

// sem seleo de backface 
m_pd3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);



Quando a iluminao  habilitada, conforme o Direct3D rasteriza uma cena no estgio final da apresentao, ele determina a cor de cada pixel apresentado baseado em uma combinao da cor do material atual ( e os texels em um mapa de textura associado), as cores difusas e do espectro da vrtice, se especificadas, to bem como a cor e a intensidade da luz produzida pelas fontes de luz na cena ou o nvel de luz do ambiente da cena. 

A projection transformation (transformao de projeo) leva em considerao os campos de viso verticais e horizontais da cmera, assim ela aplica a perspectiva  cena. Objetos que esto prximos a frente do frustrum so aumentados e objetos que esto distantes so diminudos. Ele deforma a geometria do frustrum da cmera dentro de uma forma cbica ao posicionar e ao transpor a matriz 4x4 para uma matriz de projeo perspectiva construda de um campo de viso ou frustrum de viso, proporo de aspecto, no plano prximo ou no plano frontal clipado e no plano distante ou de trs do plano clipado; isto o torna mais fcil para clipar geometricamente aquilo que fica em ambos os lados, de dentro e de fora do frustrum de viso. Voc pode pensar a transformao de projeo como controladora interna da cmara;  como escolher uma lente para a cmara.



Clipping: a geometria  clipada  forma de um cubo e a geometria clipada resultante  ento transformada em 2D por eliminar a coordenada-z e escalar os pontos para as coordenadas da tela.



Transformao Matemtica
Vamos agradecer aos nossos antigos professores de matemtica :-). Aprendi matemtica do inicio dos anos 70 at a metade dos 80 na escola (sim...ns temos um outro sistema de educao aqui na Alemanha). Naquela poca, nunca pensei que haveria um uso to interessante (i.e. programao de jogos) para ela. Gostaria de saber se os professores de matemtica de hoje em dia falam sobre o uso da matemtica em jogos de computador. 

Qualquer jogo impressionante exige transformaes corretas: considere o seguinte exemplo. Um avio, digamos um F22, est orientado de modo que seu nariz esteja apontando na direo positiva z, sua asa direita esteja apontada na direo positiva x, e seu cockpit esteja apontando na direo positiva y. Assim, o local das axis x, y e z do F22 estejam alinhadas com as axis do mundo x , y e z . Se este avio for girado 90 graus sobre sua axis y, seu nariz estaria em direo a axis do mundo x, sua asa direita em direo a axis do mundo z e seu cockpit permanecer na direo do mundo +y. Desta nova posio, vire o F22 sobre sua axis z. Se suas transformaes estiverem corretas, o avio vai girar sobre sua prpria axis z. Se suas transformaes estiverem erradas, o F22 vai girar sobre a axis z do mundo. No Direct3D voc pode garantir a transformao correta ao usar matrizes 4x4. 

Matrizes so ordens retangulares de nmeros. Uma matriz de mundo 4x4 contm quatro vetores que representam as coordenadas do world space dos vetores das unidades axis x, y e z, e as coordenadas do world space as quais so a origem destes vetores das axis: 

x x x 0
y y y 0
z z z 0
x y z 1

Vetores so um dos conceitos mais importantes em jogos de 3D; Eles so entidades matemticas que descrevem uma direo e uma magnitude (que podem, por exemplo, ser usadas para velocidade). Um vetor de propsito geral consiste de duas coordenadas. Voc pode ver a direo destes vetores ao desenhar uma linha entre as duas coordenadas. A magnitude  a distncia entre os pontos. 



A primeira coordenada  chamada de ponto inicial e a segunda de ponto final. Jogos de trs dimenses, com freqncia usam um tipo especial de vetor  o vetor livre. Seu ponto inicial pressupe-se estar na origem e somente o ponto final est especificado.

Vetores so geralmente denotados por uma letra do alfabeto em negrito, i.e a. Assim, poderamos dizer que o vetor v = (1,2,3). A primeira coluna  unidades na direo x, a segunda coluna  unidades na direo y, a terceira coluna, unidades na z.

A primeira coluna contm coordenadas do world space da axis local x. A segunda coluna contm a axis local y e a terceira coluna as coordenadas do world space da axis local z. Os vetores so unidades vetoriais cuja magnitude 1. Basicamente, as unidades vetoriais so usadas para definir direes quando a magnitude no  realmente importante. A ltima fila contm as coordenadas do world space da origem do objeto, que traduz o objeto.

Uma matriz especial  a matriz identidade:

1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1

A matriz identidade representa um conjunto de axis de objetos que esto alinhadas com as axis do mundo. A coordenada do mundo x da axis local x  1, as coordenadas do mundo y e z da axis local x so 0 e o vetor origem  (0, 0, 0). Assim a axis local do modelo x permanece diretamente na axis do mundo x. O mesmo  verdadeiro para as axis locais x e y. Assim,  uma matriz de "recuo s razes".

Esta matriz poderia ser acessada pr: 

D3DMATRIX mat;
mat._11 = 1.0f; mat._12 = 0.0f; mat._13 = 0.0f; mat._14 = 0.0f;
mat._21 = 0.0f; mat._22 = 1.0f; mat._23 = 0.0f; mat._24 = 0.0f;
mat._31 = 0.0f; mat._32 = 0.0f; mat._33 = 1.0f; mat._34 = 0.0f;
mat._41 = 0.0f; mat._42 = 0.0f; mat._43 = 0.0f; mat._44 = 1.0f;



Se uma posio de objeto no model space corresponde a sua posio no world space, simplesmente posicione a matriz de world trasformation para matriz identidade.

Uma operao tpica de transformao  uma operao de multiplicar matriz 4x4. Um engine de transformao multiplica um vetor representando dados 3D, tipicamente uma vrtice ou um vetor normal, por uma matriz 4x4. O resultado  um vetor transformado. Isto  feito com lgebra linear padro.

Matriz Vetor Vetor
Transformadora Original Transformado

a b c d x ax + by + cy + dw x'
e f g h x y = ex + fy + gz + hw = y'
i j k l z ix + jy + kz + lw z'
m n o p w mx + ny + oz + pw w'



Antes que um vetor possa ser transformado, uma matriz de transformao deve ser construda. Esta matriz engloba os dados para converter os dados do vetor em um novo sistema de coordenadas. Tal nterim de matrizes deve ser criado para cada ao (escala, rotao e transformao) que deveria ser realizado sobre o vetor. Aquelas matrizes so multiplicadas juntas para criar uma nica matriz que representa os efeitos combinados de todas aquelas aes (concatenao de matrizes). Esta nica matriz, chamada de matriz transformadora poderia ser usada para transformar um vetor ou um milho de vetores. O tempo para organizar amortiza-se pela habilidade de re- us-lo. A concatenao das matrizes do mundo, viso e projeo so manuseadas pelo Direct3D internamente. 

Um dos prs em usar multiplicao de matrizes  que escalar, rotacionar e traduzir tudo leva a mesma quantidade de tempo para se realizar. Assim a apresentao de um engine de transformao dedicado  previsvel e consistente. Isto permite aos desenvolvedores de software tomar decises formadas em relao a apresentao e a qualidade. 

A Matriz do Mundo
Geralmente a matriz do mundo  uma combinao de translao, rotao e escala de matrizes dos objetos. O cdigo para uma matriz do mundo de translao e rotao pode parecer assim:

struct Object
{
D3DVECTOR vLocation;
FLOAT fYaw, fPitch, fRoll;
...

D3DMATRIX matLocal;
};


class CMyD3DApplication : public CD3DApplication
{
...
Object m_pObjects[NUM_OBJECTS];
...
};


// in FrameMove()
for (WORD i = 0; i < dwnumberofobjects; i++)
{
D3DUtil_SetTranslateMatrix( matWorld, m_pObject[i].vLocation );

D3DMATRIX matTemp, matRotateX, matRotateY, matRotateZ;
D3DUtil_SetRotateYMatrix( matRotateY, m_pObject[i].fYaw );
D3DUtil_SetRotateXMatrix( matRotateX, m_pObject[i].fPitch );
D3DUtil_SetRotateZMatrix( matRotateZ, m_pObject[i].fRoll );
D3DMath_MatrixMultiply( matTemp, matRotateX, matRotateY );
D3DMath_MatrixMultiply( matTemp, matRotateZ, matTemp );
D3DMath_MatrixMultiply( matWorld, matTemp, matWorld );

m_pObject[i].matLocal = matWorld;
}

// in Render()
for (WORD i = 0; i < dwnumberofobjects; i++)
{
...
m_pd3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD,
&m_pObject[i].matLocal );
...
}



Voc pode tornar mais fcil para voc mesmo ao armazenar as matrizes que contenham informaes das axis em cada estrutura do objeto. Estamos somente armazenando a matriz do mundo aqui, porque o objeto em si no  animado, assim a matriz modelo no  usada. Uma coisa muito importante a lembrar  que a multiplicao da matriz no  comutativa. Isto significa [a] * [b] != [b] * [a]. A frmula para a transformao :< /FONT> 

|W| = |M| * |T| * |X| * |Y| * |Z| 

Onde M  a matriz modelo, T  a matriz de transformao e X, Y e Z so as matrizes de rotao. 

O cdigo acima traduz o objeto dentro do seu local com D3DUtil_SetTranslateMatrix(). A translao pode ser melhor descrita como uma mudana linear dentro da posio. Esta mudana pode ser representada por um vetor delta [tx, ty, tz], onde tx (com freqncia chamado de dx) representa a mudana na posio x do objeto, ty (ou dy) representa a mudana na sua posio y, e tz (ou dz) a mudana na sua posio z. Voc pode encontrar D3DUtil_SetTranslateMatrix() em d3dutil.h. inline VOID D3DUtil_SetTranslateMatrix( D3DMATRIX& m, FLOAT tx, FLOAT ty, FLOAT tz ) 



inline VOID D3DUtil_SetTranslateMatrix( D3DMATRIX& m,
FLOAT tx, FLOAT ty, FLOAT tz )
{ 
D3DUtil_SetIdentityMatrix( m );
m._41 = tx; m._42 = ty; m._43 = tz; 
}

=

1 0 0 0
0 1 0 0
0 0 1 0 
tx ty tz 1


Usando o nosso exemplo F22 acima, se o nariz do avio estiver orientado ao longo da axis local z do objeto, ento a translao deste avio na direo +z ao usar tz far que o avio se mova para frente na direo que o seu nariz est apontando. 

A prxima operao que for realizada pelo nosso cdigo  a rotao. A rotao pode ser descrita como um movimento circular sobre algumas axis. Os ngulos incrementados usados para rotacionar o objeto aqui representam a rotao da orientao atual. Isto significa, ao rotacionar 1 grau sobre a axis z, que voc estar dizendo para o objeto girar1 grau sobre a axis z da sua atual orientao, no levando em conta como voc tem a orientao. Isto  como o mundo real opera. 

D3DUtil_SetRotateYMatrix() rotaciona os objetos sobre a axis y, onde fRads iguala a quantidade que voc quer girar sobre esta axis. Voc pode encontr-lo, assim como todas as outras matrizes de rotao em d3dutil.h. 



VOID D3DUtil_SetRotateYMatrix( D3DMATRIX& mat, FLOAT fRads )
{
D3DUtil_SetIdentityMatrix( mat );
mat._11 = cosf( fRads );
mat._13 = -sinf( fRads );
mat._31 = sinf( fRads );
mat._33 = cosf( fRads );
}

=

cosf fRads 0 -sinf fRads 0
0 0 0 0
sinf fRads 0 cosf fRads 0
0 0 0 0



D3DUtil_SetRotateXMatrix() rotaciona os objetos sobre a axis x, onde fRads iguala a quantidade que voc quer rotacionar sobre esta axis: 

VOID D3DUtil_SetRotateXMatrix( D3DMATRIX& mat, FLOAT fRads )
{
D3DUtil_SetIdentityMatrix( mat );
mat._22 = cosf( fRads );
mat._23 = sinf( fRads );
mat._32 = -sinf( fRads );
mat._33 = cosf( fRads );
}

=

1 0 0 0
0 cos fRads sin fRads 0
0 -sin fRads cos fRads 0
0 0 0 0




D3DUtil_SetRotateZMatrix() rotaciona os objetos sobre a axis z, onde fRads iguala a quantidade que voc quer rotacionar sobre esta axis: 

VOID D3DUtil_SetRotateZMatrix( D3DMATRIX& mat, FLOAT fRads )
{
D3DUtil_SetIdentityMatrix( mat );
mat._11 = cosf( fRads );
mat._12 = sinf( fRads );
mat._21 = -sinf( fRads );
mat._22 = cosf( fRads );
}

=

cosf fRads sinf fRads 0 0
-sinf fRads cos fRads 0 0
0 0 0 0
0 0 0 0




O prottipo de D3DMath_MatrixMultiply() parece com VOID D3DMath_MatrixMultiply (D3DMATRIX& q, D3DMATRIX& a, D3DMATRIX& b). Em outras palavras: q=a*b. A multiplicao de matrizes  a operao pela qual uma matriz  transformada em outra. Uma multiplicao e matriz armazena resultados da soma dos produtos das filas e colunas de matrizes.< /FONT> 

a b c d A B C De f g h * E F G H = i j k l I J K L m n o p M N O P
a*A+b*E+c*I+d*M a*B+b*F+c*J+d*N a*C+b*G+c*K+d*O a*D+b*H+c*L+d*P
e*A+f*E+g*I+h*M e*B+f*F+g*J+h*N etc.
Uma rotina de multiplicao de matrizes lenta, mas compreensvel poderia parecer assim: 

VOID D3DMath_MatrixMultiply( D3DMATRIX& q, D3DMATRIX& a, D3DMATRIX& b )
{
FLOAT* pA = (FLOAT*)&a;
FLOAT* pB = (FLOAT*)&b;
FLOAT pM[16];

ZeroMemory( pM, sizeof(D3DMATRIX) );

for (WORD i=0; i< 4; i++)
for (WORD j=0; j< 4; j++)
pM [i][j]= pA[i][0] * pB[0][j] 
+ pA[i][1] * pB[1][j]
+ pA[i][2] * pB[2][j] 
+ pA[i][3] * pB[3][j];

memcpy( &q, pM, sizeof(D3DMATRIX) );
}


Uma verso mais rpida est implementada em d3dutil.h: 

VOID D3DMath_MatrixMultiply( D3DMATRIX& q, D3DMATRIX& a, D3DMATRIX& b )
{
FLOAT* pA = (FLOAT*)&a;
FLOAT* pB = (FLOAT*)&b;
FLOAT pM[16];

ZeroMemory( pM, sizeof(D3DMATRIX) );

for( WORD i=0; i<4; i++ ) 
for( WORD j=0; j<4; j++ ) 
for( WORD k=0; k<4; k++ ) 
pM[4*i+j] += pA[4*i+k] * pB[4*k+j];

memcpy( &q, pM, sizeof(D3DMATRIX) );
}


Uma vez que voc tenha construdo a matriz de transformao do mundo, voc precisa chamar o mtodo SetTransform() no mtodo de interface pblica Render() do Framework do Direct3D. Posicione a matriz de transformao do mundo, especificando o flag D3DTRANSFORMSTATE_WORLD no primeiro parmetro.

A Matriz de Viso 


A matriz de viso descreve a posio e a orientao do espectador na cena. Isto  normalmente a sua orientao e posio, olhando atravs do vidro do seu monitor em direo a cena. Este modelo de pensamento  abstrado por muitos autores ao falarem sobre a cmera atravs da qual voc est olhando para dentro da cena. 



Para fazer a translao e a rotao o espectador ou a cmera na cena, trs vetores so necessrios. Estes poderiam ser chamados de vetores LOOK(OLHAR), UP(CIMA) e RIGHT(DIREITA) 



Eles definem um conjunto de axis local para a cmera e sero posicionados no incio da aplicao no mtodo InitDeviceObjects() ou FrameMove()do framework. 

static D3DVECTOR vLook=D3DVECTOR(0.0f,0.0f,-1.0); static D3DVECTOR vUp=D3DVECTOR(0.0f,1.0f,0.0f); static D3DVECTOR vRight=D3DVECTOR(1.0f,0.0f,0.0f); 
O vetor LOOK  um vetor que descreve de que maneira a cmera est sendo mostrada.  a axis local z da cmera. Para posicionar a direo do olhar da cmera de modo que ela mostre dentro da tela, teramos que posicionar o vetor LOOK em D3DVECTOR (0, 0, 1). O vetor LOOK no  suficiente para descrever a orientao da cmera. A cmera poderia ficar de cabea para baixo e o vetor LOOK no refletir esta mudana na orientao. O vetor UP ajuda aqui; ele aponta verticalmente para cima relativo a direo que a cmera aponta.  como um axis y da cmera. Assim o vetor UP  definido como D3DVECTOR (0, 1, 0). Se voc quiser virar a cmera de cabea para baixo, o vetor UP ser D3DVECTOR (0, -1, 0). Podemos gerar um vetor RIGHT dos vetores e LOOK e UP ao usar o produto cruzado dos dois vetores. 

Tomando o produto cruzado dos dois vetores de quaisquer dois vetores forma-se um terceiro vetor perpendicular ao plano formado pelos dois primeiros. O produto cruzado  usado para determinar quais polgonos e de que maneira esto sendo mostrados. Ele usa duas bordas de polgonos para gerar um normal. Ento, ele pode ser usado para gerar um normal para qualquer superfcie pela qual voc tenha dois vetores que ficam dentro da superfcie. Diferente do produto pontilhado, o produto cruzado no  comutativo. a x b = - (b x a). A magnitude do produto cruzado de a e b, ||axb||  dada por ||a||*||b||*sin(@). A direo do vetor resultante  ortogonal para ambos a e b.< /FONT > 



Alm disto, o produto cruzado  usado para derivar a equao do plano determinado pelos dois vetores interseccionados.

Agora imagine, o jogador est sentado no cockpit do F22 ao invs de olh-lo do lado de fora. Se o jogador empurra seu pedal no seu F22 para a esquerda ou direita, os vetores LOOK e RIGHT tem de ser rotacionados sobre o vetor UP (efeito YAW ) ou axis y. se ele empurra manche de vo para a direita ou esquerda, os vetores UP e RIGHT tem de ser rotacionados ao redor do vetor LOOK (efeito ROLL ) ou axis z. Se ele empurra o seu boto de vo para frente e para trs, temos que rotacionar os vetores LOOK e UP ao redor do vetor RIGHT (efeito PITCH ) ou axix x. 

Existe um problema: quando os computadores manuseiam nmeros de pontos-flutuantes, pequenos erros de acumulao acontecem enquanto fazemos toda esta matemtica de rotao. Depois de algumas rotaes, esses erros contnuos fazem os trs vetores uniperpendiculares uns com os outros.  obviamente importante para os trs vetores ficarem em ngulos retos de cada um. A soluo  uma regenerao de vetores base, que deve ser realizada antes dos vetores serem girados ao redor de um outro. Usaremos o seguinte cdigo para lidar com a regenerao dos vetores base:

vLook = Normalize(vLook);vRight = CrossProduct( vUp, vLook); // Produto cruzado dos vetores UP e LOOK vetorvRight = Normalize (vRight);vUp = CrossProduct (vLook, vRight); // Produto cruzado dos vetores RIGHT e LOOK vUp = Normalize(vUp);
Primeiro, normalizamos o vetor LOOK de modo que seu comprimento seja 1. Os vetores com comprimentos de 1 so chamados vetores unidade ou normalizados. Para calcular um vetor unidade, divida o vetor pela sua magnitude ou comprimento. Voc pode calcular a magnitude dos vetores usando o teorema de Pitgoras: 

x+y+z = m
O comprimento do vetor  obtido por 

||A|| = sqrt (x + y + z)
 a raiz quadrado do Teorema de Pitgoras. A magnitude de um vetor tem um smbolo especial na matemtica.  um letra maiscula designada com duas barras verticais ||A||. 

Para normalizar um vetor, as seguintes funes inline no d3dvec.inl so definidas: 

inline _D3DVECTORNormalize (const _D3DVECTOR& v){ return v / Magnitude(v);}
inline D3DVALUEMagnitude (const _D3DVECTOR& v){ return (D3DVALUE) sqrt(SquareMagnitude(v));} 
inline D3DVALUESquareMagnitude (const _D3DVECTOR& v){ return v.x*v.x + v.y*v.y + v.z*v.z;}
O mtodo Normalize() divide o vetor pela sua magnitude, que  restaurado pela raiz quadrada do teorema de Pitgoras. 

sqrt()  uma funo matemtica da biblioteca math do Visual C/C++ fornecida pela Microsoft. Outros compiladores devem ter uma funo similar. 

Depois de normalizar o vetor LOOK , criamos um vetor RIGHT para determinar o produto cruzado dos vetores UP e LOOK e normaliz-lo. O vetor UP  criado do produto cruzado dos vetores LOOK e RIGHT e uma normalizao posterior. 

Depois disto, construmos as matrizes pitch, yaw e roll fora destes vetores: 

// Matrizes para pitch, yaw e roll
// isto cria uma matriz de rotao ao redor do vetor RIGHT do espectador D3DMATRIX matPitch, matYaw, matRoll;D3DUtil_SetRotationMatrix(matPitch, vRight, fPitch); 
// Cria uma matriz de rotao ao redor do vetor UP do espectador. D3DUtil_SetRotationMatrix(matYaw, vUp, fYaw ); 
// Cria uma matriz de rotao ao redor do vetor LOOK do espectador. D3DUtil_SetRotationMatrix(matRoll, vLook, fRoll);
Ao multiplicar, por exemplo, a matriz matYaw com os vetores LOOK e RIGHT, podemos girar dois vetores em volta de outro vetor. 



// agora multiplique estes vetores com as matrizes que recm criamos. // Primeiro giramos os vetores LOOK & RIGHT sobre o vetor UP D3DMath_VectorMatrixMultiply(vLook , vLook, matYaw);D3DMath_VectorMatrixMultiply(vRight, vRight,matYaw); 
// E ento giramos os vetores LOOK & UP sobre o vetor RIGHT D3DMath_VectorMatrixMultiply(vLook , vLook, matPitch);D3DMath_VectorMatrixMultiply(vUp, vUp, matPitch); 
// Agora gire os vetores RIGHT & UP sobre o vetor LOOK D3DMath_VectorMatrixMultiply(vRight, vRight, matRoll);D3DMath_VectorMatrixMultiply(vUp, vUp, matRoll);
Agora posicione a matriz de viso: 

D3DMATRIX view=matWorld;D3DUtil_SetIdentityMatrix( view );//definido em d3dutil.h e d3dutil.cpp view._11 = vRight.x; view._12 = vUp.x; view._13 = vLook.x;view._21 = vRight.y; view._22 = vUp.y; view._23 = vLook.y;view._31 = vRight.z; view._32 = vUp.z; view._33 = vLook.z;view._41 = - DotProduct( vPos, vRight ); // dot protuct definido em d3dtypes.hview._42 = - DotProduct( vPos, vUp );view._43 = - DotProduct( vPos, vLook );
m_pd3dDevice->SetTransform(D3DTRANSFORMSTATE_VIEW,&view)
=

vx ux nx 0
vy uy ny 0
vz uz nz 0
-(u * c) -(v * c) -(n * c) 1

Nesta matriz, u, n e v so os vetores de direo UP, RIGHT e LOOK, e c  a posio espacial mundial da cmera. Esta matriz contm todos os elementos necessrios para traduzir e rotacionar as vrtices do espao mundial para o espao da cmera. 

Os fatores de translao x, y e z so computados ao pegarmos o negativo do produto pontilhado entre a posio da cmera e os vetores u, v e n. Eles so negativos porque a cmera funciona o oposto para os objetos no mundo 3D. 

Para girar os dois vetores um sobre o outro, mudamos as variveis fPitch, fYaw e fRoll assim: 

fPitch=-0.3f * m_fTimeElapsed;...fPitch=+0.3f * m_fTimeElapsed;...fYaw=-0.3f * m_fTimeElapsed;...fYaw=+0.3f * m_fTimeElapsed;...fRoll=-0.3f * m_fTimeElapsed;...fRoll=+0.3f * m_fTimeElapsed;... 


Para sincronizar o nmero diferente de razo de frames com o comportamento dos objetos, temos que usar uma varivel com o tempo decorrido desde o ltimo frame. Para mover a cmera para frente e para trs usamos a varivel de posio 

vPos.x+=fspeed*vLook.x;vPos.y+=fspeed*vLook.y;vPos.z+=fspeed*vLook.z; 
vPos.x-=fspeed*vLook.x;vPos.y-=fspeed*vLook.y;vPos.z-=fspeed*vLook.z;


A Matriz de Projeo 
Uma transformao interessante  a projeo de perspectiva, a qual  usada em Direct3D. Ela converte o frustrum de viso da cmera (a forma de pirmide que define o que a cmera pode ver) em um espao de cubo, conforme visto acima (com uma forma geomtrica de cubo, clipando  muito mais fcil) . Objetos prximos a cmera so grandes, enquanto objetos distantes so menores. Onde, linhas paralelas no sero mais paralelas aps a projeo. Esta transformao aplica perspectiva a cena 3D; ela projeta a geometria 3D para dentro de uma forma que pode ser visualizada em uma tela 2D. 



A matriz de projeo  ajustada com D3DUtil_SetProjectionMatrix() dentro de d3dutil.cpp. 

HRESULT D3DUtil_SetProjectionMatrix( 
D3DMATRIX& mat, FLOAT fFOV, FLOAT fAspect, FLOAT fNearPlane,
FLOAT fFarPlane ) { if(
fabs(fFarPlane-fNearPlane)
< 0.01f ) return
E_INVALIDARG; if(
fabs(sin(fFOV/2)) < 0.01f )
return E_INVALIDARG;

FLOAT w = fAspect * ( cosf(fFOV/2)/sinf(fFOV/2) );
FLOAT h = 1.0f * ( cosf(fFOV/2)/sinf(fFOV/2) );
FLOAT Q = fFarPlane / ( fFarPlane - fNearPlane );

ZeroMemory( &mat, sizeof(D3DMATRIX) );
mat._11 = w;
mat._22 = h;
mat._33 = Q;
mat._34 = 1.0f;
mat._43 = -Q*fNearPlane;

return S_OK;
}

=

w 0 0 0
0 h 0 0
0 0 Q 1
0 0 -QZN 0



Este cdigo estabelece uma matriz de projeo, pegando a razo aspecto, plano frontal (-Q*Zn) ou prximo e planos de trs e distante e o campo de viso com fFOV em radianos. Note que a matriz de projeo  normalizada pelo elemento [3][4] a ser1.0. Isto  realizado de modo que o alcance de w-based do nevoeiro funcione corretamente. 

Depois desta ltima transformao, a geometria deve ser clipada ao espao do cubo e convertida das coordenadas homogneas para as coordenadas da tela, dividindo as coordenadas x, y e z de cada ponto por w. O Direct3D realiza estes passos internamente. 

Coordenadas homogneas: Apenas pense em uma matriz 3x3. Conforme voc aprendeu acima, em uma matriz 4x4, os primeiros trs elementos, digamos i, j e k, na quarta fila so necessrios para traduzir o objeto. Com matrizes 3x3 um objeto no pode ser traduzido sem mudar a sua posio. Se voc adicionar algum vetor (representando translao) aos vetores i, j e k, a orientao deles tambm mudar. Assim, precisamos uma quarta dimenso com as tais chamadas coordenadas homogneas. 

Neste espao 4D, cada ponto tem um quarto componente que mede a distncia ao longo de uma axis imaginria de quarta dimenso chamada w. Para converter um ponto 4D em um ponto 3D, voc tem que dividir cada componente por x, y, z e w por w. Assim cada multiplicao de um ponto cujo componente w seja igual a 1 representa aquele mesmo ponto. Por exemplo: (4, 2, 8, 2) representa o mesmo ponto como em (2, 1, 4, 1). 

Para descrever distncia sobre a axis w, precisamos de um outro vetor l. Ele aponta na direo da axis w e sua magnitude neutra  1, como os outros vetores. 

No Direct3D, os pontos permanecem homogneos, mesmo depois de serem enviados atravs da pipeline geomtrica. Somente depois de clipar, quando a geometria estiver pronta para ser mostrada, estaro estes pontos convertidos dentro de coordenadas cartesianas por diviso de cada componente por w.


Antes de fazer a essncia da transformao, normalmente o porto de viso  posicionado pelo Framework do Direct3D IM Framework. Ele define como os componentes horizontais, verticais e de profundidade das coordenadas de um polgono no espao de um cubo, sero escalados antes do polgono ser mostrado.



Indo para os cdigos
Os exemplos usam (como comum nesta srie) o framework do Direct3D. A classe de aplicao em objetos animados .cpp parece assim:

class CMyD3DApplication : public CD3DApplication
{
D3DVERTEX m_pvObjectVertices[16];
WORD m_pwObjectIndices[30];
Object m_pObjects[2];

FLOAT m_fStartTimeKey, // Referncia de tempo para clculos
m_fTimeElapsed;

static HRESULT ConfirmDevice( DDCAPS* pddDriverCaps, 
D3DDEVICEDESC7* pd3dDeviceDesc );

protected:
HRESULT OneTimeSceneInit();
HRESULT InitDeviceObjects();
HRESULT FrameMove( FLOAT fTimeKey );
HRESULT Render();
HRESULT DeleteDeviceObjects();
HRESULT FinalCleanup();

public:
CMyD3DApplication();
}; 



Os objetos so descritos pelas vrtices em m_pvObjectVertices[16] e pelos ndices em m_pwObjectIndices[30]. H uma estrutura de objeto chamada object. O movimento independente de fps  garantido pelas variveis de dois tempos, que englobam o tempo inicial e o decorrido entre os dois frames. Como usual, ConfirmDevice(),  chamado mtodo de primeiro framework, mas no  usado aqui porque ns no precisamos de nenhuma capacidade especial da placa 3D. Os outros mtodos de framework so chamados de top - down e sero mencionados nesta ordem nos pargrafos seguintes.

OneTimeSceneInit()
A funo OneTimeSceneInit() realiza basicamente qualquer alocao de fonte de um tempo, e  chamada uma vez por ciclo de execuo de aplicao. Aqui ela contm o cdigo para construir os dois objetos.

HRESULT CMyD3DApplication::OneTimeSceneInit()
{
// Pontos e normais que formam um objeto geomtrico
D3DVECTOR p1 = D3DVECTOR( 0.00f, 0.00f, 0.50f );
D3DVECTOR p2 = D3DVECTOR( 0.50f, 0.00f,-0.50f );
D3DVECTOR p3 = D3DVECTOR( 0.15f, 0.15f,-0.35f );
D3DVECTOR p4 = D3DVECTOR(-0.15f, 0.15f,-0.35f );
D3DVECTOR p5 = D3DVECTOR( 0.15f,-0.15f,-0.35f );
D3DVECTOR p6 = D3DVECTOR(-0.15f,-0.15f,-0.35f );
D3DVECTOR p7 = D3DVECTOR(-0.50f, 0.00f,-0.50f );
D3DVECTOR n1 = Normalize( D3DVECTOR( 0.2f, 1.0f, 0.0f ) );
D3DVECTOR n2 = Normalize( D3DVECTOR( 0.1f, 1.0f, 0.0f ) );
D3DVECTOR n3 = Normalize( D3DVECTOR( 0.0f, 1.0f, 0.0f ) );
D3DVECTOR n4 = Normalize( D3DVECTOR(-0.1f, 1.0f, 0.0f ) );
D3DVECTOR n5 = Normalize( D3DVECTOR(-0.2f, 1.0f, 0.0f ) );
D3DVECTOR n6 = Normalize( D3DVECTOR(-0.4f, 0.0f, -1.0f ) );
D3DVECTOR n7 = Normalize( D3DVECTOR(-0.2f, 0.0f, -1.0f ) );
D3DVECTOR n8 = Normalize( D3DVECTOR( 0.2f, 0.0f, -1.0f ) );
D3DVECTOR n9 = Normalize( D3DVECTOR( 0.4f, 0.0f, -1.0f ) );

// Vrtices para o topo
m_pvObjectVertices[ 0] = D3DVERTEX( p1, n1, 0.000f, 0.500f );
m_pvObjectVertices[ 1] = D3DVERTEX( p2, n2, 0.500f, 1.000f );
m_pvObjectVertices[ 2] = D3DVERTEX( p3, n3, 0.425f, 0.575f );
m_pvObjectVertices[ 3] = D3DVERTEX( p4, n4, 0.425f, 0.425f );
m_pvObjectVertices[ 4] = D3DVERTEX( p7, n5, 0.500f, 0.000f );

// Vrtices para baixo
...
// Vrtices para trs
...

O projeto exemplo mostra um objeto simples. Bem... um cubo pode aborrecer voc. O modelo wireframe mostra os polgonos e pontos do objeto. 

Point #1 is m_pvObjectVertices[0] and m_pvObjectVertices[5], point #2 is m_pvObjectVertices[1] and m_pvObjectVertices[6], point #3 is m_pvObjectVertices[3] and m_pvObjectVertices[11], etc. 

Cada ponto  declarado como um vetor com D3DVECTOR. Para cada face do objeto, um normal  definido de modo que haja nove normais.

O vetor normal  usado em mdulo de sombras Gouraud , para controlar a iluminao e fazer alguns efeitos de texturizao. As aplicaes do Direct3D no precisam especificar as faces normais; o sistema as calcula automaticamente quando elas so necessrias.

Os vetores normais so normalizados com uma chamada em

D3DVECTOR n1 = Normalize( D3DVECTOR( 0.2f, 1.0f, 0.0f ) );
O mtodo Normalize() divide o vetor pela sua magnitude, que  recuperado pela raiz quadrada do Teorema de Pitgoras.

As ltimas duas variveis do D3DVERTEX so coordenadas de textura. A maioria das texturas, como bitmats, so uma apresentao de duas dimenses de valores de cores. Os valores individuais da cor so chamados elementos de textura, ou texels. Cada texel tem um nico endereo na textura: sua coordenada texel. Os programas do Direct3D especificam as coordenadas texel em termos de valores u, v, muito parecidos com coordenadas cartesianas 2D que so especificadas em termos de coordenadas x, y. O endereo pode ser encontrado como um nmero de coluna ou fila. Contudo, a fim de mapear texels em cima das primitivas, o Direct3D exige uma mdia de endereo uniforme para todos os texels em todas as texturas. Entretanto, ele usa um esquema de endereamento genrico no qual todos os endereos texel esto em uma variao de 0.0 at 1.0 inclusive.

O Direct3D mapeia texels no espao da textura diretamente para os pixels no espao da tela. O espao da tela  um frame de referncia no qual as coordenadas esto relacionadas diretamente as locaes 2D no buffer do frame, para serem mostradas em um monitor ou outro dispositivo de visualizao. As coordenadas do espao de projeo so convertidas para as coordenadas do espao da tela , usando uma matriz de transformao criada dos parmetros do porto de viso. Este processo exemplificado  chamado de filtragem de textura. H quatro mtodos de filtragem de processo suportado peloDirtect3D: Amostra de Ponto mais Prximo; Filtragem de Textura Linear; Filtragem de Textura Anisotrpica; Filtragem de Textura com Mipmaps.

No estamos usando uma textura aqui, iremos falar sobre isso no Tutorial #3 . 

Agora na prxima parte do mtodo OneTimeSceneInit():

// ndices das Vrtices para o objeto
m_pwObjectIndices[ 0] = 0; m_pwObjectIndices[ 1] = 1; m_pwObjectIndices[2] = 2;m_pwObjectIndices[ 3] = 0; m_pwObjectIndices[ 4] = 2; m_pwObjectIndices[5] = 3;m_pwObjectIndices[ 6] = 0; m_pwObjectIndices[ 7] = 3; m_pwObjectIndices[8] = 4;m_pwObjectIndices[ 9] = 5; m_pwObjectIndices[10] = 7; m_pwObjectIndices[11] = 6;m_pwObjectIndices[12] = 5; m_pwObjectIndices[13] = 8; m_pwObjectIndices[14] = 7;m_pwObjectIndices[15] = 5; m_pwObjectIndices[16] = 9; m_pwObjectIndices[17] = 8;m_pwObjectIndices[18] = 10; m_pwObjectIndices[19] = 15; m_pwObjectIndices[20] = 11;m_pwObjectIndices[21] = 11; m_pwObjectIndices[22] = 15; m_pwObjectIndices[23] = 12;m_pwObjectIndices[24] = 12; m_pwObjectIndices[25] = 15; m_pwObjectIndices[26] = 14;m_pwObjectIndices[27] = 12; m_pwObjectIndices[28] = 14; m_pwObjectIndices[29] = 13;
Este pedao de cdigo gera os ndices para o D3DPT_TRIANGLELIST chamar DrawIndexedPrimitive(). O Direct3D lhe permite definir os polgonos em uma das duas maneiras: pr definir suas vrtices ou pr definir ndices dentro de uma lista de vrtices. A ltima abordagem  geralmente mais rpida e mais flexvel, por causa dos objetos com polgonos mltiplos para os dados da vrtice dividida. O objeto consiste de somente sete pontos que so usados pelas 15 vrtices. 

H duas maneiras de agrupar as vrtices que definem uma primitiva: usando primitivas no indexadas e indexadas. Para criar uma primitiva no indexada, voc preenche uma apresentao com uma lista ordenada de vrtices. Ordenada significa que a ordem das vrtices na apresentao indica como construir os tringulos. O primeiro tringulo consiste das trs primeiras vrtices, o segundo consiste das prximas trs vrtices e assim por diante. Se voc tem dois tringulos que so conectados, ter que especificar as mesmas vrtices mltiplas vezes. Para criar uma primitiva indexada, voc preenche uma apresentao com uma lista de vrtices no ordenadas e especifica a ordem com uma segunda apresentao ( apresentao de ndice). Isso significa que as vrtices podem ser divididas por tringulos mltiplos, simplesmente por ter mltiplas entradas na apresentao do ndice referindo-se a mesma vrtice. A maioria dos modelos 3D divide um nmero de vrtices. Entretanto, voc pode salvar uma banda larga e o tempo de CPY dividindo estas vrtices entre os mltiplos tringulos. 

Definindo os ndices dentro de uma lista de vrtices tem uma desvantagem: o custo da memria. Poderia haver problemas com as vrtices divididas de um cubo. A iluminao de um cubo  feita ao usar suas faces normais que est perpendicular ao plano das faces. Se as vrtices de um cubo esto divididas, h somente uma vrtice dividida para dois tringulos. Esta vrtice dividida tem somente uma normal para calcular a face normal, assim o efeito de iluminao no seria o que voc quer.

Em OneTimeSceneInit() os dois objetos so definidos com a ajuda da estrutura m_pObjects. 

...
// objeto amarelo m_pObjects[0].vLoc = D3DVECTOR(-1.0f, 0.0f, 0.0f); m_pObjects[0].fYaw = 0.0f; m_pObjects[0].fPitch = 0.0f; m_pObjects[0].fRoll = 0.0f; m_pObjects[0].r = 1.0f; m_pObjects[0].g = 0.92f; m_pObjects[0].b = 0.0f; // objeto vermelho
m_pObjects[1].vLoc = D3DVECTOR(1.0f, 0.0f, 0.0f);
m_pObjects[1].fYaw = 0.0f; m_pObjects[1].fPitch = 0.0f; m_pObjects[1].fRoll = 0.0f; m_pObjects[1].r = 1.0f; m_pObjects[1].g = 0.0f; m_pObjects[1].b = 0.27f; 
return S_OK;
}
Para a posio do primeiro objeto na tela, uma locao tem de ser escolhida. O objeto amarelo deveria estar localizado na esquerda e o vermelho no lado direito. As cores para as propriedades dos materiais so escolhidas nas variveis r, g e b. Elas so posicionadas mais tarde na funo framework Render() com uma chamada em

// objeto amarelo// Posiciona a cor para o objetoD3DUtil_InitMaterial( mtrl, m_pObjects[0].r, m_pObjects[0].g, m_pObjects[0].b );m_pd3dDevice->SetMaterial( &mtrl );


InitDeviceObjects()
O InitDeviceObjects()  usado para inicializar objetos por dispositivo, tais como carregar bitmaps sobre uma superfcie de dispositivo, posicionar matrizes e popular buffers de vrtices. Primeiro, usaremos aqui um conjunto de um material. Quando a iluminao estiver capacitada, conforme o Direct3D rasteriza uma cena no estgio final da apresentao, ele determina a cor de cada pixel apresentado baseado em uma combinao de cor do material atual (e os texels em um mapa de textura associado), as cores difusas e especulares na vrtice, se especificadas, to bem como a cor e a intensidade de luz produzida pelas fontes de luz na cena ou no nvel de luz do ambiente da cena.

Voc deve usar materiais para apresentar uma cena se voc estiver deixando o Direct3D manusear a iluminao. 

HRESULT CMyD3DApplication::InitDeviceObjects(){ D3DMATERIAL7 mtrl; D3DUtil_InitMaterial( mtrl, 1.0f, 1.0f, 1.0f ); m_pd3dDevice->SetMaterial( &mtrl );...
Por padro, nenhum material  selecionado. Quando nenhum material  selecionado, o engine de iluminao do Direct3D  desligado. 

D3DUtil_InitMaterial() posiciona os valores de RGBA do material. Os valores de cores dos materiais representam quanto de componente de luz dada  refletida pela superfcie que est apresentada com aquele material. Uma propriedade do material inclui reflexo difuso, reflexo do ambiente, emisso de luz e iluminao especular. 

Reflexo difuso: define como o polgono reflete a iluminao difusa (qualquer luz que no venha do ambiente de luz). Isto  descrito em termos de uma cor, que representa a melhor cor refletida por um polgono. Outras cores so refletidas em menor proporo que diferentes so da cor difusa. 
Reflexo do Ambiente: define como o polgono reflete a iluminao do ambiente. Isto  descrito em termos de uma cor, que como ao reflexo difuso, representa a cor melhor refletida pelo polgono. 
Emisso de Luz: faz o polgono aparecer para emitir uma certa cor (isto na verdade, no ilumina o mundo; somente a aparncia do polgono). 
Iluminao especular: descreve quanto brilhante o polgono . 
Um material cuja s componentes da cor so R: 1.0, G: 1.0, B: 1.0, A: 1.0 refletir toda a luz que vem em seu caminho. Assim como, um material com R: 0.0, G: 1.0, B: 0.0, A: 1.0 refletir toda a luz verde que  direcionada a ele. SetMaterial() coloca as propriedades do material para o dispositivo. 

Depois de posicionar o material, podemos montar a luz. Os valores das cores para as fontes de luz representam a quantidade de um componente em particular de luz que ele emite. As luzes no usam um componente alfa, assim voc s precisa pensar em componentes de cor vermelho, verde e azul. Voc pode visualizar os trs componentes como lentes verdes, verdes e azuis de um projetor de televiso. Cada lente pode estar desligada (um valor 0.0 em um membro apropriado), ela pode ser to brilhante quanto possvel (como um valor 1.0) ou algum nvel entre isto. As cores vindas de cada lente combinam para fazer a cor final da luz. Uma combinao como R: 1.0, G: 1.0, B: 1.0 cria uma luz branca, onde R: 0.0, G: 0.0, B: 0.0 resulta em uma luz que no emite luz na verdade. Voc pode fazer uma luz que emita somente um componente, resultando em uma luz puramente vermelha, verde ou azul, ou a luz poderia usar combinaes para emitir cores como amarelo ou roxo. Voc pode at mesmo posicionar os valores de componentes de luz para criar uma "luz escura" que na verdade remova a luz da cena. Ou, voc pode posicionar os componentes para alguns valores maiores que 1.0 para criar uma luz extremamente brilhante. O Direct3D emprega trs tipos de luzes: luzes de pontos, spotlights, e luzes direcionadas. 

Voc escolhe o tipo de luz que quer quando voc cria um conjunto de propriedades de luz. As propriedades de iluminao e o resultado geral computacional variam com cada tipo de fonte de luz. Os seguintes tipos de fontes de luz so apoiados Direct3D 7: 

Luzes de Ponto 
Spotlights 
Luzes direcionadas 
O DirectX 7.0 no usa o tipo de luz de ponto paralelo oferecido em verses anteriores do DirectX. Dica: voc deve evitar spotlights, porque existem maneiras mais realistas de criar spotlights do que o mtodo padro fornecido pelo Direct3D, tais como mistura de texturas: veja os tutoriais de "Multitexturizao" .

A amostra cria um ambiente de luz e, se a sua placa de vdeo suportar, duas luzes direcionais.

... // Posicione as luzes m_pd3dDevice->SetRenderState( D3DRENDERSTATE_AMBIENT, 0x0b0b0b0b); if( m_pDeviceInfo->ddDeviceDesc.dwVertexProcessingCaps & D3DVTXPCAPS_DIRECTIONALLIGHTS ) { D3DLIGHT7 light; if( m_pDeviceInfo->ddDeviceDesc.dwMaxActiveLights > 0 ) { D3DUtil_InitLight( light, D3DLIGHT_DIRECTIONAL, 0.5f, -1.0f, 0.3f ); m_pd3dDevice->SetLight( 0, &light ); m_pd3dDevice->LightEnable( 0, TRUE ); } if( m_pDeviceInfo->ddDeviceDesc.dwMaxActiveLights > 1 ) { D3DUtil_InitLight( light, D3DLIGHT_DIRECTIONAL, 0.5f, 1.0f, 1.0f ); light.dcvDiffuse.r = 0.5f; light.dcvDiffuse.g = 0.5f; light.dcvDiffuse.b = 0.5f; m_pd3dDevice->SetLight( 1, &light ); m_pd3dDevice->LightEnable( 1, TRUE ); } m_pd3dDevice->SetRenderState( D3DRENDERSTATE_LIGHTING, TRUE );}...
Uma luz ambiente est efetivamente em todo o lugar na cena.  um nvel geral que preenche uma cena inteira, no importando os objetos e suas localizaes dentro da cena. A luz ambiente est em todo lugar, no importando a direo ou posio. H somente cor e intensidade. SetRenderState() coloca ao luz ambiente ao especificar D3DRENDERSTATE_AMBIENT como o parmetro dwRenderStateType , e a cor desejada RGBA com o parmetro dwRenderState . Tenha em mente que os valores da cor do material representam quanto de componente de luz fornecida  refletida pela superfcie. Assim, as propriedades de luz no so as nicas propriedades que so responsveis pela cor do objeto que voc v. 

Em adio, h as luzes direcionais superiores e inferiores usadas pelo exemplo. Apesar de usarmos luzes direcionais e uma luz para iluminar os objetos na cena, elas so independentes umas das outras. As luzes direcionais sempre tm cor, e  o fator para algoritmos de sombras, tais como o sombreamento de Gouraud.  equivalente a usar uma fonte de ponto de luz em uma distncia infinita.. 

O primeiro exemplo confere as capacidades do dispositivo grfico. Se ele suportar luz direcional, a luz ser posicionada ao chamarmos o mtodo SetLight(), que usa a estrutura D3DLIGHT7.

typedef struct _D3DLIGHT7 { D3DLIGHTTYPE dltType; D3DCOLORVALUE dcvDiffuse; D3DCOLORVALUE dcvSpecular; D3DCOLORVALUE dcvAmbient; D3DVECTOR dvPosition; D3DVECTOR dvDirection; D3DVALUE dvRange; D3DVALUE dvFalloff; D3DVALUE dvAttenuation0; D3DVALUE dvAttenuation1; D3DVALUE dvAttenuation2; D3DVALUE dvTheta; D3DVALUE dvPhi; } D3DLIGHT7, *LPD3DLIGHT7;
A variao de posio, as propriedades atenuantes so usadas para definir uma localizao de luz no espao do mundo e como a luz se comporta sobre a distncia. O mtodo D3DUtil_InitLight() em d3dutil.cpp posiciona poucos valores default .

VOID D3DUtil_InitLight( D3DLIGHT7& light, D3DLIGHTTYPE ltType, FLOAT x, FLOAT y, FLOAT z ){ ZeroMemory( &light, sizeof(D3DLIGHT7) ); light.dltType= ltType; light.dcvDiffuse.r = 1.0f; light.dcvDiffuse.g = 1.0f; light.dcvDiffuse.b = 1.0f; light.dcvSpecular = light.dcvDiffuse; light.dvPosition.x = light.dvDirection.x = x; light.dvPosition.y = light.dvDirection.y = y; light.dvPosition.z = light.dvDirection.z = z; light.dvAttenuation0 = 1.0f; light.dvRange = D3DLIGHT_RANGE_MAX;} 
Somente a posio da luz  colocada explicitamente para a primeira luz. A posio da luz  descrita usando um D3DVECTOR com as coordenadas x, y e z no mundo espacial. A primeira luz  localizada acima destas. A Segunda luz somente  posicionada se o dispositivo grfico a suporta.  um pouco mais escura. 

Luzes direcionais no usam variao e variveis atenuantes. Uma propriedade de variao de luz determina a distncia, no espao do mundo, no que uma malha em uma cena no mais receba luz. Assim o valor ponto flutuante dvRange representa a variao mxima de luz. As variveis de atenuao controlam como a intensidade da luz diminui at a distncia mxima, especificada pela propriedade de variao. H trs valores atenuantes, controlando uma constante de luz, atenuao linear e quadrtica com variveis de ponto flutuante. Muitas aplicaes colocam o membro dvAttentuation1 para 1.0f e as outras para 0.0f. 

Abaixo do material e luzes, o mtodo InitDeviceObjects() coloca a matriz de projeo e a razo aspecto do porto de viso. 

FrameMove()
O mtodo FrameMove() manuseia a maioria da entrada dos teclados e matrizes. Todas as rotaes e tradues para os objetos e a cmera so colocados neste mtodo.

No incio voc precisa de um manual DirectInput para entender todas as coisas sobre input apresentadas neste mtodo.

Com DirectInput, que  o componente de entrada do DirectX, voc pode acessar teclado, mouse, joystick e todas as formas de dispositivos de entrada de uma maneira uniforme. Apesar do DirectInput ser extremamente complexo, se voc usar toda a sua funcionalidade, ele pode ser muito manuseado no mais baixo nvel de funcionalidade, e  o que usaremos aqui. 

O DirectInput consiste de DLLs e 2 arquivos para compilao: dinput.lib e dinput.h. So necessrios estes arquivos para usar o DirectInput.

Configurando DirectInput:

Criar um objeto principal de DirectInput com DirectInputCreateEx() 
Criar um ou mais dispositivos de entrada com CreateDeviceEx() 
Colocar o formato dos dados de cada dispositivo com SetDataFormat() 
Colocar o nvel cooperativo para cada dispositivo com SetCooperativeLevel() 
Conseguindo um input:

Adquira cada dispositivo input com Acquire() 
Receba Input com GetDeviceState() 
Joysticks especiais: chame Poll() se necessrio 
O DirectInput pode enviar-lhe informao de modo imediato ou em buffer de entrada, time-stamped (tempo demarcado) em um formato de mensagem. Somente usaremos o modo de aquisio de dados imediato aqui ( veja a documentao do DirectX SDK para informaes em modo buffered ).

Ns chamamos DirectInputCreateEx() no mtodo CreateDInput().

HRESULT CMyD3DApplication::CreateDInput( HWND hWnd )
{
// teclado
if( FAILED(DirectInputCreateEx( (HINSTANCE)GetWindowLong( hWnd, GWL_HINSTANCE ),
DIRECTINPUT_VERSION,
IID_IDirectInput7,
(LPVOID*) &g_Keyboard_pDI, NULL) ) )
return 0;

return S_OK;
}

 chamado em WinMain() com

// Cria o Objeto DInput
if( FAILED(d3dApp.CreateDInput( d3dApp.Get_hWnd() ) ) )
return 0; 



Para restaurar a instncia do exemplo, usamos GetWindowLong( hWnd, GWL_HINSTANCE ). A constante DIRECTINPUT_VERSION determina se a verso do DirectInput  projetada para isso. O prximo parmetro  a Interface desejada do DirectInput, que deve ser usada pelo exemplo. Valores aceitveis so IID_IDirectInput, IID_IDirectInput2 e IID_IDirectInput7. Para a compatibilidade com verses anteriores, voc pode definir uma verso mais antiga do DirectInput ali. Isto  til, por exemplo, para o WinNT que suporta somente DirectX 3. O ltimo parmetro da interface do DirectInput abriga o ponteiro.

Para criar um dispositivo de entrada  o teclado  usamos CreateDeviceEx() em CreateInputDevice()

HRESULT CMyD3DApplication::CreateInputDevice( HWND hWnd,
LPDIRECTINPUT7 pDI,
LPDIRECTINPUTDEVICE2 pDIdDevice, 
GUID guidDevice,
const DIDATAFORMAT* pdidDataFormat,
DWORD dwFlags )
{
// Pega uma interface para input device
if( FAILED( pDI->CreateDeviceEx( guidDevice, 
IID_IDirectInputDevice2,
(VOID**)&pDIdDevice, NULL ) ) )
return 0;

// Ajusta o device data format
if( FAILED( pDIdDevice->SetDataFormat( pdidDataFormat ) ) )
return 0;

// ajusta cooperativity level
if( FAILED( pDIdDevice->SetCooperativeLevel( hWnd, dwFlags ) ) )
return 0;

if(guidDevice == GUID_SysKeyboard)
g_Keyboard_pdidDevice2 = pDIdDevice;

return S_OK;
} 



 chamado em WinMain() 


// Cria o dispositivo do tecladoif( FAILED(d3dApp.CreateInputDevice( d3dApp.Get_hWnd(), 
d3dApp.g_Keyboard_pDI, 
d3dApp.g_Keyboard_pdidDevice2, 
GUID_SysKeyboard, 
&c_dfDIKeyboard,
DISCL_NONEXCLUSIVE | DISCL_FOREGROUND))) 
Alm de criar um dispositivo input, ele posiciona o formato dos dados do teclado com SetDataFormat() e o nvel de cooperatividade com SetCooperativeLevel(). O primeiro parmetro do CreateDeviceEx()  o GUID (Identificador nico global), que identifica o dispositivo que voc quer criar.Voc tem que enumerar os dispositivos com EnumDevices(), para conseguir os GUIDs para qualquer coisa estranha como joysticks, flightsticks, lemes e conjuntos de realidade virtual. 

Voc no precisar realizar um processo de enumerao para o teclado, porque todos os computadores tm um. Assim o GUID para teclados  pr-definido pelo DirectInput. O prximo parmetro  para a interface desejada. Valores aceitveis so atualmente IID_DirectInputDevice, IID_DirectInputDevice2 e IID_DirectInputDevice7. O CreateDeviceEx() retorna o ponteiro da interface pDIdDevice que ser armazenada mais tarde no g_Keyboard_pdidDevice2 

Ao posicionar o ponteiro de dados com SetDataFormat(), voc dir ao DirectInput como voc quer que os dados do dispositivo sejam formatados e representados. Voc pode definir a sua prpria estrutura DIDATAFORMAT, ou voc pode usar uma constante global pr-definida: c_dfDIKeyboard  a constante para o teclado. Geralmente, voc no vai precisar definir uma estrutura customizada, porque as pr-definidas lhe permitem a sua aplicao usar a maioria dos dispositivos de fora da prateleira. 

O prximo passo que voc precisa realizar antes de poder acessar o dispositivo DirectInput (neste caso o teclado)  usar o mtodo SetCooperativeLevel() para colocar o comportamento do dispositivo. Ele determina como o input do dispositivo  dividido com ouras aplicaes. Para um teclado voc tem que usar a bandeira DISCL_NONEXCLUSIVE, porque o DirectInput no suporta acesso exclusivo para os dispositivos de teclado.

E mesmo Ctrl+Alt+Esc no funcionaria com um teclado exclusivo.

O DISCL_FOREGROUND limita o uso do DirectInput sobre o primeiro plano. O dispositivo  automaticamente no adquirido quando a janela associada move-se para o fundo. Enquanto que o DISCL_BACKGROUND d ao app a possibilidade para usar o DirectInputDevice em primeiro ou ltimo plano.

Em adio, este mtodo precisa do handle de uma janela para posicionar a exclusividade.

Para conseguir a entrada do teclado chamamos, dentro do mtodo FrameMove(), as seguintes funes: 

BYTE diks[256]; // DInput keyboard state bufferZeroMemory( diks, sizeof(diks) ); 
if (FAILED(g_Keyboard_pdidDevice2->GetDeviceState( sizeof(diks), &diks ))){ g_Keyboard_pdidDevice2->Acquire(); if (FAILED(g_Keyboard_pdidDevice2->GetDeviceState( sizeof(diks), &diks ))) return 0;}


o array disks[256] armazena os estados do teclado . Para conseguir acesso ao DirectInput Device, voc tem que adquiri-lo. Voc restaura os estados do teclado com GetDeviceState(). Os valores usados com 

// objeto amareloif (diks[DIK_J] &&0x80) // tecla j m_pObjects[0].fRoll -= 1.0f * m_fTimeElapsed;


Para testar se qualquer tecla est pressionada, voc deve testar o bit 0x80 no byte 8-bit tecla que est sendo verificada; em outras palavras o bit pr-dominante. 

No final do exemplo, o dispositivo DirectInput  liberado com uma chamada para

VOID CMyD3DApplication:estroyInputDevice(){ // teclado if(g_Keyboard_pdidDevice2) { g_Keyboard_pdidDevice2->Unacquire(); g_Keyboard_pdidDevice2->Release(); g_Keyboard_pdidDevice2 = NULL; }}
Isso  tudo com DirectInput. Agora voltamos a programao grfica.

O FrameMove() usa um cdigo de tempo para assegurar que todos os objetos e a cmera movem-se/giram na mesma velocidade em todas as possveis fps. 

// cdigo de tempo: // o objeto deve mover-se/girar na mesma velocidade// em todas as possveis fpsconst cTimeScale = 5;// calcular o tempo decorridom_fTimeElapsed= (fTimeKey-m_fStartTimeKey)*cTimeScale;// armazene o ltimo tempom_fStartTimeKey=fTimeKey; 


Para calcular o tempo decorrido, voc precisa subtrair m_fStartTimeKey de fTimeKey.

Para girar o objeto amarelo sobre sua axis x e z, precisamos mudar as variveis fRoll e fPitch na estruturam_pObject. 

// objeto amareloif (diks[DIK_J] &&0x80) // j key m_pObjects[0].fRoll -= 1.0f * m_fTimeElapsed; 
if (diks[DIK_L] &&0x80) // l key m_pObjects[0].fRoll += 1.0f * m_fTimeElapsed; 
if (diks[DIK_I] &&0x80) // i key m_pObjects[0].fPitch -= 1.0f * m_fTimeElapsed; 
if (diks[DIK_K] &&0x80) // k key m_pObjects[0].fPitch += 1.0f * m_fTimeElapsed;


Eles so usados nos seguintes mtodos de matriz de translao e rotao:

D3DMATRIX matWorld; 
// Matriz do objeto para o objeto amareloD3DUtil_SetTranslateMatrix( matWorld, m_pObjects[0].vLoc ); 
D3DMATRIX matTemp, matRotateX, matRotateY, matRotateZ;D3DUtil_SetRotateYMatrix( matRotateY, -m_pObjects[0].fYaw );D3DUtil_SetRotateXMatrix( matRotateX, -m_pObjects[0].fPitch );D3DUtil_SetRotateZMatrix( matRotateZ, -m_pObjects[0].fRoll );D3DMath_MatrixMultiply( matTemp, matRotateX, matRotateY );D3DMath_MatrixMultiply( matTemp, matRotateZ, matTemp );D3DMath_MatrixMultiply( matWorld, matTemp, matWorld ); 
m_pObjects[0].matLocal = matWorld; 


Como descrito acima, o mtodo D3DUtil_SetTranslateMatrix() faria a translao do objeto amarelo dentro do seu local e D3DUtil_SetRotateXMatrix() e D3DUtil_SetRotateZMatrix() faria a rotao dele ao redor da axis x e da axis z. No usaremos D3DUtil_SetRotateYMatrix() aqui. Eles sero teis para os prximos tutoriais. Por ltimo, a posio do objeto amarelo na matriz do mundo ser armazenada na estrutura m_pObjects. 

A mesma funcionalidade fica atrs do cdigo para o objeto vermelho.

// objeto vermelhoif (diks[DIK_D] &&0x80) // Key d m_pObjects[1].fRoll -= 1.0f * m_fTimeElapsed; 
if (diks[DIK_A] &&0x80) // Key a m_pObjects[1].fRoll += 1.0f * m_fTimeElapsed; 
if (diks[DIK_S] &&0x80) // Key s m_pObjects[1].fPitch -= 1.0f * m_fTimeElapsed; 
if (diks[DIK_W] &&0x80) // Key w m_pObjects[1].fPitch += 1.0f * m_fTimeElapsed; 
// object matrix for red objectD3DUtil_SetTranslateMatrix( matWorld, m_pObjects[1].vLoc ); D3DUtil_SetRotateYMatrix( matRotateY, -m_pObjects[1].fYaw );D3DUtil_SetRotateXMatrix( matRotateX, -m_pObjects[1].fPitch );D3DUtil_SetRotateZMatrix( matRotateZ, -m_pObjects[1].fRoll );D3DMath_MatrixMultiply( matTemp, matRotateX, matRotateY );D3DMath_MatrixMultiply( matTemp, matRotateZ, matTemp );D3DMath_MatrixMultiply( matWorld, matTemp, matWorld ); 
m_pObjects[1].matLocal = matWorld; 
As nicas diferenas so o uso de outras teclas e o armazenamento das variveis em outra estrutura de objeto. 

Depois de fazer a translao dos objetos, a cmera tem que ser colocada e apontada na direo da direita. Os vetores vLook, vUp, vRight e vPos esto armazenando as posies e os vetores LOOK, UP e RIGHT da cmera. 

// **************************************************
**********
// coisas da cmera
// **************************************************
**********
static D3DVECTOR vLook=D3DVECTOR(0.0f,0.0f,1.0);static D3DVECTOR vUp=D3DVECTOR(0.0f,1.0f,0.0f);static D3DVECTOR vRight=D3DVECTOR(1.0f,0.0f,0.0f);static D3DVECTOR vPos=D3DVECTOR(0.0f,0.0f,-5.0f);FLOAT fPitch,fYaw,fRoll;fPitch = fYaw = fRoll = 0.0f; 
FLOAT fspeed= 1.0f * m_fTimeElapsed;
O vetor LOOK aponta na direo da axiz z positiva. O vetor UP aponta em direo da axis y positiva e o vetor RIGHT aponta em direo da axiz x positiva. As variveis fPitch, fYaw e fRoll so responsveis pela orientao da cmera. A cmera move-se para trs e para frente com vPos, enquanto que speed realiza a velocidade para frente e para trs. 

// fPitchif (diks[DIK_UP] && 0x80) fPitch=-0.3f * m_fTimeElapsed; 
if (diks[DIK_DOWN] && 0x80) fPitch=+0.3f * m_fTimeElapsed; 
// fYawif (diks[DIK_C] && 0x80) // c key fYaw=-0.3f * m_fTimeElapsed; 
if (diks[DIK_X] && 0x80) // x key fYaw=+0.3f * m_fTimeElapsed; 
// fRollif (diks[DIK_LEFT] && 0x80) fRoll=-0.3f * m_fTimeElapsed; 
if (diks[DIK_RIGHT] && 0x80) fRoll=+0.3f * m_fTimeElapsed; 
// camera para frenteif (diks[DIK_HOME] && 0x80 ) // Key HOME { vPos.x+=fspeed*vLook.x; vPos.y+=fspeed*vLook.y; vPos.z+=fspeed*vLook.z;} 
// camera para trsif (diks[DIK_END] &&0x80 ) // Key END { vPos.x-=fspeed*vLook.x; vPos.y-=fspeed*vLook.y; vPos.z-=fspeed*vLook.z;}
Os trs vetores de orientao so normalizados com o Vetor de Base de Regenerao, ao normalizar o vetor LOOK, construindo um vetor perpendicular fora dos vetores UP e LOOK, normalizando o vetor RIGHT e construindo o vetor perpendicular dos vetores LOOK e RIGHT, o vetor UP. Ento o vetor UP  normalizado.

A normalizao produz um vetor com uma magnitude de 1. O mtodo de produto cruzado produz um vetor, que  perpendicular aos dois vetores fornecidos como variveis. 

vLook = Normalize(vLook);vRight = CrossProduct( vUp, vLook); // Produto cruzado dos vetores UP e LOOK vRight = Normalize (vRight);vUp = CrossProduct (vLook, vRight); // Produto cruzado dos vetores RIGHT e LOOK vUp = Normalize(vUp);


As matrizes de rotao so construidas com D3DUtil_SetRotationMatrix() e executadas com D3DUtil_MatrixMultiply() 

// Matrizes para pitch, yaw e roll// Isto cria uma matriz de rotao ao redor do vetor RIGHT do espectador. D3DMATRIX matPitch, matYaw, matRoll;D3DUtil_SetRotationMatrix(matPitch, vRight, fPitch); 
// Cria uma matriz de rotao ao redor do vetor UP do espectador. D3DUtil_SetRotationMatrix(matYaw, vUp, fYaw ); 
// Cria uma matriz de rotao ao redor do vetor LOOK do espectador D3DUtil_SetRotationMatrix(matRoll, vLook, fRoll);
// agora multiplique estes vetores com as matrizes que recm criamos // Primeiro rotacionamos os vetores LOOK & RIGH sobre o vetor UP D3DMath_VectorMatrixMultiply(vLook , vLook, matYaw);D3DMath_VectorMatrixMultiply(vRight, vRight,matYaw);
// e ento giramos os vetores LOOK & UP sobre o vetor RIGHT D3DMath_VectorMatrixMultiply(vLook , vLook, matPitch);D3DMath_VectorMatrixMultiply(vUp, vUp, matPitch); 
// agora giramos os vetores RIGHT & UP sobre o vetor LOOK D3DMath_VectorMatrixMultiply(vRight, vRight, matRoll);D3DMath_VectorMatrixMultiply(vUp, vUp, matRoll); 
D3DMATRIX view=matWorld;D3DUtil_SetIdentityMatrix( view );// definido em d3dutil.h e d3dutil.cpp view._11 = vRight.x; view._12 = vUp.x; view._13 = vLook.x;view._21 = vRight.y; view._22 = vUp.y; view._23 = vLook.y;view._31 = vRight.z; view._32 = vUp.z; view._33 = vLook.z;view._41 = - DotProduct( vPos, vRight ); // produto pontilhado definido em d3dtypes.hview._42 = - DotProduct( vPos, vUp );view._43 = - DotProduct( vPos, vLook ); 
m_pd3dDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &view);


Render()
O mtodo Render()  chamado uma vez por frame e  o ponto de entrada para a renderizao 3d . Ele limpa a rea de viso, e renderiza os dois objetos com material apropriado.

HRESULT CMyD3DApplication::Render(){ D3DMATERIAL7 mtrl;
// Limpa o area de viso m_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET 3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0L ); // Inicia a cena if( FAILED( m_pd3dDevice->BeginScene() ) ) return S_OK; // Don't return a "fatal" error
// objeto amarelo // Coloca a cor para o objeto D3DUtil_InitMaterial( mtrl, m_pObjects[0].r, m_pObjects[0].g, m_pObjects[0].b ); m_pd3dDevice->SetMaterial( &mtrl );
// Aplica a matriz local do objeto m_pd3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &m_pObjects[0].matLocal ); 
// Desenha o objeto m_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, D3DFVF_VERTEX, m_pvObjectVertices, 16, m_pwObjectIndices, 30, 0 );
Estamos usando um Z-Buffer aqui ao chamar m_pd3dDevice->SetRenderState( D3DRENDERSTATE_ZENABLE, TRUE ); 
em InitDeviceObjects() e limpando o z-buffer com Clear() mostrado acima. No  grande coisa... ? Mas o Z-Buffer desempenha um papel na tarefa da determinao da superfcie visvel. Desabilite-o e voc ver o que eu quero dizer. Polgonos mais prximos a cmera devem ocultar os polgonos que esto mais distantes. H um nmero de solues para esta tarefa, por exemplo desenhando todos os polgonos de trs para a frente, que  lento e no suportada pela maioria dos hardwares, rvores BSP (Partio Espao Binria), Octrees e assim por diante. O Direct3D suporta a criao de uma superfcie de um DirectDraw que armazena informaes de profundidade para cada pixel na tela. Antes de mostrar o seu mundo virtual, o Direct3D limpa todos os pixels no buffer de profundidade at o valor mais profundo possvel. Ento quando for rasterizar, o Direct3D determina a profundidade de cada pixel sobre o polgono.  o pixel mais prximo da cmera que  armazenado, se o pixel  visivel, o valor de profundidade  armazenado no buffer de profundidade . Este processo continuar at que todos os pixels estejam desenhados. 

No h somente um Z-Buffer , mas h tambm W-Buffer. Pense no W-Buffer como um Z-Buffer de alta qualidade , que no  suportado no hardware to freqente quanto os Z-Buffers. Ele reduz problemas exibidos nos Z-Buffers como objetos em uma distncia e uma performance constante para ambos objetos prximos e distantes. Voc s precisa substituir TRUE (verdadeiro) na chamada de SetRenderState() atravs de D3DZB_USEW para us-lo. 

O mtodo Render() usa o BeginScene()/EndScene() em conjunto. A primeira funo  chamada antes de realizar a renderizao, a segunda depois disto. O BeginScene faz com que o sistema confira suas estruturas de dados internos, disponibilidade e a validade das superfcies de renderizao, e posiciona uma flag interna para assinalar que uma cena est em progresso. Se voc chamar os mtodos de renderizao quando uma cena no estiver em progresso, a funo falhar retornando D3DERR_SCENE_NOT_IN_SCENE. Uma vez que a sua renderizao esteja completa, voc precisa chamar o EndScene(). Ele limpa o flag interno que indica que uma cena est em progresso, faz o fluxo dos dados armazenados e assegura que as superfcies de apresentao estejam OK.

O segundo parmetro do DrawIndexedPrimitive(), D3DFVF_VERTEX, descreve o formato da vrtice usada para este conjunto de primitivas. O arquivo de cabealho d3dtypes.h declara estas flags e descreve explicitamente um formato de vrtice e fornece macros que agem como combinaes de tais flags.

#define D3DFVF_VERTEX ( D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1 )
Cada um dos mtodos de renderizao do IDirect3Ddevice7 aceita uma combinao destas flags e as usa para determinar como renderizar os primitivos. Basicamente, estas flags nos falam do sistema que os componentes da vrtice  posio, normal, cores, e o nmero das coordenadas da textura  sua aplicao usa e, indiretamente, quais partes do pipeline de renderizao voc quer que o Direct3D aplique sobre elas. Alm disto, a presena ou ausncia de um formato de flag de vrtice em particular comunica ao sistema quais campos componentes da vrtice esto presentes na memria, sua aplicao pode conservar a memria e minimizar a largura da banda processada exigida aos modelos apresentados.. 

D3DFVF_XYZ inclui a posio de uma vrtice no transformada. Voc tem de especificar uma vrtice normal, um componente de vrtice de cor (D3DFVF_DIFFUSE ou D3DFVF_SPECULAR), ou incluir ao menos um conjunto de coordenadas de textura (D3DFVF_TEX1 atravs D3DFVF_TEX8). D3DFVF_NORMAL mostra que o formato da vrtice inclui um vetor normal de vrtice e D3DFVF_TEX1 mostra-nos o nmero dos conjuntos de coordenadas de textura para esta vrtice. Aqui est um conjunto de coordenadas de textura. 

O formato da vrtice no iluminada e no transformada  equivalente a estrutura mais antiga pr DirectX 6 do D3DVERTEX:

typedef struct _D3DVERTEX { union { D3DVALUE x; /* Coordenadas homogneas */ D3DVALUE dvX; };
union { D3DVALUE y; D3DVALUE dvY; };
union { D3DVALUE z; D3DVALUE dvZ; };
union { D3DVALUE nx; /* Normal */ D3DVALUE dvNX; };
union { D3DVALUE ny; D3DVALUE dvNY; };
union { D3DVALUE nz; D3DVALUE dvNZ; };
union { D3DVALUE tu; /* Coordenadas das texturas */ D3DVALUE dvTU; };
union { D3DVALUE tv; D3DVALUE dvTV; };


DeleteDeviceObjects()
Este mtodo no  usado aqui. Est vazio.



FinalCleanup()
Aqui, liberamos o dispositivo do DirectInput. Voc deveria usar este mtodo no DeleteDeviceObjects(), porque se voc alterar, por exemplo, da modalidade janela para tela cheia, o dispositivo ser removido toda vez. 

HRESULT CMyD3DApplication::FinalCleanup(){ // libere o teclado DestroyInputDevice();
return S_OK;
}


Final
Espero que tenha gostado da nossa pequena viajem no mundo do Framework e transformao do Direct3D 7 IM . Isto ser um trabalho em desenvolvimento no futuro. Se voc encontrar algum erro ou se voc tiver algumas boas idias para melhorar este tutorial ou se voc no gostou dele, me d um sinal no endereo wolf@direct3d.net.

